#include <unistd.h>
#include <cstdint>
#include <iostream>
#include <vector>
#include <memory>
#include <unordered_map>
#include <functional>

using taskFunc = std::function<void()>;
using realeaseFunc = std::function<void()>;

class TimerTask
{
public:
    TimerTask(uint64_t id, uint32_t delayTime, const taskFunc& cb)
        :_id(id), _timeout(delayTime), _task_cb(cb), _canceled(false)
    {}
    //设置定时任务执行回调
    void SetRealeaseFunc(const realeaseFunc& realease_cb)
    {
        _realease_cb = realease_cb;
    }

    uint32_t DelayTime()
    {
        return _timeout;
    }

    void Cancel()
    {
        _canceled = true;
    }

    //在析构中执行定时任务和_realease_cb
    ~TimerTask()
    {
        if (!_canceled) { _task_cb(); }
        _realease_cb();
    }

private:
    uint64_t _id; //定时任务对象id
    uint32_t _timeout; //定时任务超时时间
    taskFunc _task_cb; //定时任务回调
    realeaseFunc _realease_cb; //定时任务执行回调
    bool _canceled; //任务是否被取消
};

class TimerWheel
{
public:
    TimerWheel()
        :_tick(0), _capacity(60), _wheel(_capacity)
    {}
    //添加定时任务
    void TimerTaskAdd(uint64_t id, uint32_t delayTime, const taskFunc& cb)
    {
        //创建定时任务管理对象
        taskPtr taskPt(new TimerTask(id, delayTime, cb));
        //设置任务执行回调
        taskPt->SetRealeaseFunc(std::bind(&TimerWheel::TaskRealeaseFunc, this, id));
        //将定时任务进行管理
        taskWeakPtr taskWpt(taskPt);
        // _timerTasks.insert(std::make_pair(id, taskWpt)); //Cancel之后立即Add相同id的任务，任务不会被Add成功
        _timerTasks[id] = taskWpt; //Cancel之后立即Add相同id的任务，任务可以被Add(替换)成功
        //将定时任务管理对象添加到时间轮
        int pos = (_tick + delayTime) % _capacity;
        _wheel[pos].push_back(taskPt);
    }
    //延时定时任务
    void TimerTaskRefresh(uint64_t id)
    {
        auto iter = _timerTasks.find(id);
        if (iter == _timerTasks.end()) { return; }
        taskPtr taskPt = iter->second.lock(); //获取weak_ptr对应的shared_ptr对象
        //计算新的时间轮位置，并将新的任务管理对象加入时间轮
        int pos = (_tick + taskPt->DelayTime()) % _capacity;
        _wheel[pos].push_back(taskPt);
    }
    //定时任务取消
    //被取消的定时任务不会被立即回调和realease,而是在超时时进行
    void TaskCancel(int id)
    {
        auto iter = _timerTasks.find(id);
        if (iter == _timerTasks.end()) { return; }
        taskPtr taskpt = iter->second.lock();
        //如果任务管理对象未过期，就取消对应的任务
        if (taskpt) { taskpt->Cancel(); }
    }
    //启动时间轮
    //需要每秒钟执行一次
    void Run()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }

    ~TimerWheel() {}

private:
    using taskPtr = std::shared_ptr<TimerTask>;
    using taskWeakPtr = std::weak_ptr<TimerTask>;

private:
    void TaskRealeaseFunc(uint64_t id)
    {
        //在定时任务管理表中移除对应的任务
        auto iter = _timerTasks.find(id);
        if (iter == _timerTasks.end()) { return; }
        _timerTasks.erase(iter);
    }

private:
    uint32_t _tick; //时间轮指针
    uint32_t _capacity; //表盘大小(最大超时时间)
    std::vector<std::vector<taskPtr>> _wheel; //时间轮
    std::unordered_map<uint64_t, taskWeakPtr> _timerTasks; //定时任务管理
};

class Test
{
public:
    Test() {
        std::cout << "Test::Test()" << std::endl;
    }

    ~Test() {
        std::cout << "Test::~Test()" << std::endl;
    }
};

void TaskTest(Test* t)
{
    delete t;
}

int main()
{
    TimerWheel tw;
    Test* t(new Test());
    tw.TimerTaskAdd(66, 5, std::bind(TaskTest, t));
    std::cout << "任务添加..." << std::endl;
    for (int i = 0; i < 5; ++i)
    {
        tw.Run();
        tw.TimerTaskRefresh(66);
        std::cout << "任务延时..." << std::endl;
        sleep(1);
    }
    tw.TaskCancel(66);
    std::cout << "任务取消..." << std::endl;
    while (true) {
        tw.Run();
        std::cout << "tick..." << std::endl;
        sleep(1);
    }
    return 0;
}